package project3;

import java.net.Socket;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;

public class IntermediateRouter {
	private Map<Integer, Integer> routingTable;
	private Map<Integer, Socket> inSocket;
	private Map<Integer, Socket> outSocket;
	private Map<Socket, Thread> inSocketThreadMap;
	private Map<Socket, Thread> outSocketThreadMap;
	
	// maps a Tor socket its WriterThread's buffer
	private Map<Socket, BlockingQueue<Cell>> outBufferMap;
	
	// maps from circuit id to CreateWorkerThread
	// Map<Integer, CreateWorkerThread> createWorkerThreadMap;
	
	private Socket servicePort;
	
	public IntermediateRouter(int port) {
		if (routingTable == null) {
			this.routingTable = new ConcurrentHashMap<Integer, Integer>();
			this.inSocket = new ConcurrentHashMap<Integer, Socket>();
			this.outSocket = new ConcurrentHashMap<Integer, Socket>();
			//TODO: Create new socket bind with the given port.
			//      Throw exception if creation failed.
		}
	}
	
	/**
	 * 
	 * Listen new request and handle it. 
	 */
	public void handleNewRequest() {
		
	}
	
	/**
	 * Change a cell's circuit id field to routingTable.get(destCircId)
	 * @param srcCircId
	 * @param srcCell
	 * @return
	 */
	public Cell setMappedCircuitId (int srcCircId, Cell srcCell) {
		// TODO: handle the case when srcCircId is the last hop on a circuit (i.e. end router case)
		int destCircId = routingTable.get(srcCircId);
		srcCell.setCircId(destCircId);
		
		return srcCell;
	}
	
	/**
	 * Put cell to the WriterThread buffer corresponsing to the cell's circuit field
	 * @param cell
	 */
	public void putToMappedCircuitBuffer (Cell cell) {

		int destCircId = cell.getCircId();
		Socket writeToSocket;
		BlockingQueue<Cell> buffer;
		
		writeToSocket = outSocket.get(destCircId);
		buffer = outBufferMap.get(writeToSocket);		
		
		boolean isFull = buffer.offer(cell);
		if (isFull) 
			System.out.println("[IntermediateRouter] WARNING: buffer for circuit " + destCircId +
					" at Socket " + writeToSocket + " is full.");		
	}
	
	/**
	 * Returns true iff routing table indicates that circId is the last hop on the circuit 
	 * @param circId
	 * @return
	 */
	public boolean isEndRouter (int circId) {
		// TODO: implement
		return false;
	}
	
	/**
	 * Populate the stream table
	 * @param streamId
	 * @param hostname
	 * @param port
	 */
	public void associateStreamWithWebserver(int streamId, String hostname, int port) {
		
	}

	/**
	 * called by ReaderThreads
	 * @param circId
	 * @param createIsSuccessful
	 */
	public void wakeUpCreateWorker (int circId, boolean createIsSuccessful) {
		// check if createWorkerThreadMap has key circId
		// if yes, this router is currently waiting for a response for circuit
		// creation with id circId, so we wake it up
	}
}
